#include "CrackRequest.h"
#include <sstream>

using namespace std;

CrackRequest::CrackRequest(unsigned int connID, string hash, string lower, string upper, unsigned int& next_blockid)
{
	complete = false;
	password = "";
	this->connID = connID;
	this->hash = string(hash);

	blocks.push_back(Block(next_blockid,lower,upper));

	next_blockid++;
}

bool CrackRequest::is_complete()
{
	if(complete) return true;
	for(int i = 0; i<(int)blocks.size(); ++i)
	{
		if(blocks[i].get_status() != Block::COMPLETE)
		{
			return false;
		}
	}
	complete = true;
	return true;
}

int CrackRequest::num_in_work() const
{
	int num = 0;
	for(int i = 0; i<(int)blocks.size(); ++i)
	{
		if(blocks[i].get_status() == Block::IN_WORK)
		{
			++num;
		}
	}
	return num;
}

string CrackRequest::get_block_for_worker(unsigned int& block_id)
{
	//Find block that has not been started.
	//If all blocks have been started, find block that has not been finished.
	int block_index = -1;
	for(int i = 0; i<(int)blocks.size(); ++i)
	{
		if(blocks[i].get_status() == Block::NOT_STARTED)
		{
			block_index = i;
			break;
		}
		else if(block_index == -1 && blocks[i].get_status() == Block::IN_WORK)
		{
			block_index = i;
		}
	}
	//If no blocks are found, return empty string
	if(block_index == -1)
	{
		return "";
	}

	//Set block id
	block_id = blocks[block_index].get_id();

	//Set IN_WORK
	blocks[block_index].set_status(Block::IN_WORK);

	//If block is found return formatted string:
	//hash startPoint endPoint
	//This string can be sent to the worker over LSP.
	//Worker sends back one of the following:
	//hash startPoint endPoint password
	//hash startPoint endPoint
	ostringstream oss;
	oss << "c " << hash << " " << blocks[block_index].get_sp() << " " << blocks[block_index].get_ep();
	return oss.str();
}

bool CrackRequest::set_password(string new_password)
{
	//TODO: Test if new_password matches hash

	//If new_password does NOT match hash
	//return false;

	//If new_password matches hash
	password = new_password;
	complete = true;
	return true;
}

string CrackRequest::get_result_string()
{
	if(is_complete() && password.length() > 0)
	{
		ostringstream oss;
		oss << "f " << password;
		return oss.str();
	}
	else if(is_complete() && password.length() == 0)
	{
		return string("x");
	}
	else
	{
		return NULL;
	}
}
